package com.roseski.service.impl;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.transaction.Transactional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.roseski.dao.RoseskiGoodsMapper;
import com.roseski.dao.RoseskiMemberMapper;
import com.roseski.dao.RoseskiOrderDtlMapper;
import com.roseski.dao.RoseskiOrderMapper;
import com.roseski.dao.RoseskiPayOrderMapper;
import com.roseski.dto.OrderDtlReq;
import com.roseski.dto.OrderDtlResp;
import com.roseski.dto.OrderListResp;
import com.roseski.dto.OrderReq;
import com.roseski.dto.PageDto;
import com.roseski.dto.ServiceResult;
import com.roseski.enums.OrderStatusEnum;
import com.roseski.enums.PayOrderStatusEnum;
import com.roseski.model.RoseskiGoods;
import com.roseski.model.RoseskiMember;
import com.roseski.model.RoseskiOrder;
import com.roseski.model.RoseskiOrderDtl;
import com.roseski.model.RoseskiPayOrder;
import com.roseski.service.RoseskiOrderService;
import com.roseski.service.SequenceService;
import com.roseski.util.Constants;
import com.roseski.util.ErrorCodeEnum;
import com.roseski.util.MoneyUtil;
import com.roseski.util.OkHttpUtils;

import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

@Service
public class RoseskiOrderServiceImpl implements RoseskiOrderService {
	
	Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	RoseskiMemberMapper roseskiMemberMapper;
	@Autowired
	RoseskiOrderMapper roseskiOrderMapper;
	@Autowired
	RoseskiOrderDtlMapper roseskiOrderDtlMapper;
	@Autowired
	RoseskiPayOrderMapper roseskiPayOrderMapper;
	@Autowired
	RoseskiGoodsMapper roseskiGoodsMapper;
	@Autowired
	SequenceService sequenceService;
	@Autowired
	RedisServiceImpl redisServiceImpl;
	@Value("${merchantId}")
	private String merchantId;
	@Value("${cardUrl}")
	private String cardUrl;

	@Override
	@Transactional
	public RoseskiPayOrder createOrder(OrderReq req, RoseskiMember member) {
		//创建总单
		RoseskiOrder order = buildOrder(req, member);
		//创建细单
		List<OrderDtlReq> list = req.getProductions();
		List<RoseskiOrderDtl> orderDtlList = new ArrayList<RoseskiOrderDtl>();
		long orderMoney = 0;
		for(OrderDtlReq dtl : list) {
			RoseskiOrderDtl orderDtl = buildOrderDtl(order.getOrderNo(), dtl);
			orderMoney = orderMoney + orderDtl.getMoney();
			orderDtlList.add(orderDtl);
		}
		order.setOrderMoney(orderMoney);
		order.setPayMoney(orderMoney);
		//创建支付单
		RoseskiPayOrder payOrder = buildPayOrder(order);
		roseskiOrderMapper.insert(order);
		roseskiOrderDtlMapper.insertBatch(orderDtlList);
		roseskiPayOrderMapper.insert(payOrder);
		return payOrder;
	}
	
	private RoseskiOrder buildOrder(OrderReq req, RoseskiMember member) {
		RoseskiOrder order = new RoseskiOrder();
		order.setOrderNo(createOrderNo());
		order.setMemberId(member.getMemberId());
		order.setNickName(member.getNickName());
		order.setOrderStatus(OrderStatusEnum.CREATE.name());
		order.setSettleTime(new Date());
		order.setThemeId(req.getThemeId());
		order.setCreateTime(new Date());
		order.setThemeUrl(req.getThemeImgUrl());
		return order;
	}
	
	private RoseskiOrderDtl buildOrderDtl(String orderNo, OrderDtlReq dtl) {
		RoseskiGoods goods = roseskiGoodsMapper.selectByPrimaryKey(dtl.getPId());
		RoseskiOrderDtl orderDtl = new RoseskiOrderDtl();
		orderDtl.setCreateTime(new Date());
		orderDtl.setGoodsId(dtl.getPId());
		orderDtl.setGoodsName(goods.getGoodsName());
		orderDtl.setGoodsNum(dtl.getPCount().intValue());
		orderDtl.setUnitPrice(goods.getPrice());
		orderDtl.setMoney(goods.getPrice() * dtl.getPCount());
		orderDtl.setOrderDtlNo(createOrderDtlNo());
		orderDtl.setOrderNo(orderNo);
		return orderDtl;
	}
	
	private RoseskiPayOrder buildPayOrder(RoseskiOrder order) {
		RoseskiPayOrder payOrder = new RoseskiPayOrder();
		payOrder.setCreateTime(new Date());
		payOrder.setMoney(order.getOrderMoney());
		payOrder.setOrderNo(order.getOrderNo());
		payOrder.setPayOrderNo(createPayOrderNo());
		payOrder.setPayer(order.getMemberId());
		payOrder.setPayee(merchantId);
		payOrder.setStatus(PayOrderStatusEnum.CREATE.name());
		return payOrder;
	}
	
	private String createOrderNo()
	{
		Date date = new Date();
		String datePart = new SimpleDateFormat("yyyyMMdd").format(date);
		StringBuffer ticketId = new StringBuffer();
		ticketId.append(datePart);
		DecimalFormat df = new DecimalFormat("0000000000");
		ticketId.append(df.format(sequenceService.generateSequenceNum(Constants.ORDERNO)));
		return ticketId.toString();
	}
	
	private String createOrderDtlNo()
	{
		Date date = new Date();
		String datePart = new SimpleDateFormat("yyyyMMdd").format(date);
		StringBuffer ticketId = new StringBuffer();
		ticketId.append(datePart);
		DecimalFormat df = new DecimalFormat("0000000000");
		ticketId.append(df.format(sequenceService.generateSequenceNum(Constants.ORDERDTLNO)));
		return ticketId.toString();
	}
	
	private String createPayOrderNo()
	{
		Date date = new Date();
		String datePart = new SimpleDateFormat("yyyyMMdd").format(date);
		StringBuffer ticketId = new StringBuffer();
		ticketId.append(datePart);
		DecimalFormat df = new DecimalFormat("0000000000");
		ticketId.append(df.format(sequenceService.generateSequenceNum(Constants.PAYORDERNO)));
		return ticketId.toString();
	}

	@Transactional
	@Override
	public void updateSuccessStatus(String payOrderNo, String transactionId, Date payTime) throws IOException {
		RoseskiPayOrder payOrder = roseskiPayOrderMapper.selectByPrimaryKey(payOrderNo);
		payOrder.setPayTime(payTime);
		payOrder.setTransactionId(transactionId);
		payOrder.setStatus(PayOrderStatusEnum.SUCCESS.name());
		roseskiPayOrderMapper.updateByPrimaryKeySelective(payOrder);
		RoseskiOrder order = roseskiOrderMapper.selectByPrimaryKey(payOrder.getOrderNo());
		order.setOrderStatus(OrderStatusEnum.SUCCESS.name());
		roseskiOrderMapper.updateByPrimaryKeySelective(order);
		//调用卡券接口生成卡券
    	/*OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(10, TimeUnit.SECONDS);
        builder.writeTimeout(60, TimeUnit.SECONDS);
        builder.readTimeout(60, TimeUnit.SECONDS);
        builder.sslSocketFactory(OkHttpUtils.createSSLSocketFactory());
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        OkHttpClient httpClient = builder.build();
        Map<String, List<CardTicketReq>> data = new HashMap<String, List<CardTicketReq>>();
        List<RoseskiOrderDtl> lst = roseskiOrderDtlMapper.listByOrderNo(order.getOrderNo());
        List<CardTicketReq> req = new ArrayList<>();
        for(RoseskiOrderDtl dtl : lst) {
        	RoseskiGoods goods = roseskiGoodsMapper.selectByPrimaryKey(dtl.getGoodsId());
        	CardTicketReq r = new CardTicketReq();
        	r.setCard_id(goods.getCardId());
        	r.setCount(String.valueOf(dtl.getGoodsNum()));
        	req.add(r);
        }
        data.put("card_list", req);
        RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), 
        		JSONObject.toJSONString(data));
        Request request = new Request.Builder().url("https://sp.tkfun.site/coupon/dispatch").post(requestBody).build();
        Response response = httpClient.newCall(request).execute();
        if (response.isSuccessful()){
        	JSONObject jsonObject = JSONObject.parseObject(response.body().string());
        	String show_qrcode_url = jsonObject.getString("show_qrcode_url"); 
        	if(StringUtils.isEmpty(show_qrcode_url)) {
        		logger.error("请求发券接口出错, 请求信息:{}, 响应信息:{}", response) ;
        		throw new RuntimeException("获取不到二维码信息");
        	}
        	logger.info(show_qrcode_url);
        }else {
        	logger.error("请求发券接口出错, 请求信息:{}, 响应信息:{}", response) ;
        	throw new RuntimeException("请求发券接口出错:" + response);
        }*/
	}

	@Override
	public RoseskiOrder queryOrderByOrderNo(String orderNo) {
		return roseskiOrderMapper.selectByPrimaryKey(orderNo);
	}

	@Override
	public PageDto<OrderListResp> listByMemberId(Long memberId, Integer page, Integer pageSize) throws IOException {
		PageHelper.startPage(page, pageSize);
		PageDto<OrderListResp> dto = new PageDto<OrderListResp>();
		Page<OrderListResp> list = (Page<OrderListResp>)roseskiOrderMapper.listByMemberId(memberId);
		dto.setCount(list.getTotal());
		if(!CollectionUtils.isEmpty(list)) {
			for(OrderListResp order : list) {
				List<OrderDtlResp> arr = new ArrayList<>();
				order.setTotalPrice(MoneyUtil.convertFenToYuan(Integer.parseInt(order.getTotalPrice())));
				List<RoseskiOrderDtl> lst = roseskiOrderDtlMapper.listByOrderNo(order.getPId());
				int count = 0;
				for(RoseskiOrderDtl dtl : lst) {
					OrderDtlResp resp = new OrderDtlResp();
					resp.setGoodsName(dtl.getGoodsName());
					resp.setGoodsPrice(MoneyUtil.convertFenToYuan(dtl.getMoney()));
					arr.add(resp);
					count = count + dtl.getGoodsNum();
					/*if(OrderStatusEnum.SUCCESS.name().equals(order.getOrderStatus())) {
						JSONObject object = queryCardInfo(dtl);
						resp.setCardInfo(object);
					}*/
				}
				if(OrderStatusEnum.SUCCESS.name().equals(order.getOrderStatus())) {
					order.setReceiveCount(0);
				}else {
					order.setReceiveCount(count);
				}
				order.setTotalCount(count);
				order.setGoodsList(arr);
			}
		}
		dto.setList(list);
		return dto;
	}
	
	@SuppressWarnings("deprecation")
	private JSONObject queryCardInfo(List<RoseskiOrderDtl> lists) throws IOException{
		OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(10, TimeUnit.SECONDS);
        builder.writeTimeout(60, TimeUnit.SECONDS);
        builder.readTimeout(60, TimeUnit.SECONDS);
        builder.sslSocketFactory(OkHttpUtils.createSSLSocketFactory());
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
        OkHttpClient httpClient = builder.build();
        Map<String, List<String>> map = new HashMap<String, List<String>>();
        List<String> list = new ArrayList<String>();
        //获取卡券信息
        for(RoseskiOrderDtl dtl : lists) {
	        RoseskiGoods goods = roseskiGoodsMapper.selectByPrimaryKey(dtl.getGoodsId());
	        for(int i = 0; i<dtl.getGoodsNum(); i++) {
	        	list.add(goods.getCardId());
	        }
        }
        map.put("card_ids", list);
        RequestBody requestBody = FormBody.create(MediaType.parse("application/json; charset=utf-8"), 
        		JSONObject.toJSONString(map));
        Request request = new Request.Builder().url(cardUrl).post(requestBody).build();
        Response response = httpClient.newCall(request).execute();
        if (response.isSuccessful()){
        	JSONObject jsonObject = JSONObject.parseObject(response.body().string());
        	logger.info("调用卡券接口响应信息:" + jsonObject);
        	if(jsonObject == null) {
        		logger.error("请求发券接口出错, 请求信息:{}, 响应信息:{}", response) ;
        		throw new RuntimeException("获取不到二维码信息");
        	}
        	jsonObject.remove("msg");
        	jsonObject.remove("status");
        	return jsonObject;
        }else {
        	logger.error("请求发券接口出错, 请求信息:{}, 响应信息:{}", response) ;
        	throw new RuntimeException("请求发券接口出错:" + response);
        }
	}

	/**
	 * 更新可领取
	 * @throws IOException 
	 */
	@Override
	@Transactional
	public ServiceResult<String> updateReceiveStatus(String orderNo){
		ServiceResult<String> ret = new ServiceResult<String>();
		ret.setCode(ErrorCodeEnum.SUCCESS.getCode());
		ret.setMessage(ErrorCodeEnum.SUCCESS.getMsg());
		RoseskiOrder order = roseskiOrderMapper.selectByPrimaryKey(orderNo);
		if(order == null) {
			ret.setCode(ErrorCodeEnum.ORDER_NOT_EXISTIS.getCode());
			ret.setMessage(ErrorCodeEnum.ORDER_NOT_EXISTIS.getMsg());
			return ret;
		}
		//调用生成卡券
		RoseskiOrder params = new RoseskiOrder();
		params.setOrderNo(orderNo);
		params.setOrderStatus(OrderStatusEnum.RECEIVED.name());
		roseskiOrderMapper.updateByPrimaryKeySelective(params);
		return ret;
	}

	@SuppressWarnings("unchecked")
	@Override
	public ServiceResult<JSONObject> getCardMessage(String orderNo) throws IOException {
		ServiceResult<JSONObject> ret = new ServiceResult<JSONObject>();
		ret.setCode(ErrorCodeEnum.SUCCESS.getCode());
		ret.setMessage(ErrorCodeEnum.SUCCESS.getMsg());
		RoseskiOrder order = roseskiOrderMapper.selectByPrimaryKey(orderNo);
		if(order == null) {
			ret.setCode(ErrorCodeEnum.ORDER_NOT_EXISTIS.getCode());
			ret.setMessage(ErrorCodeEnum.ORDER_NOT_EXISTIS.getMsg());
			return ret;
		}
		if(!StringUtils.isEmpty(order.getCardInfo())) {
			ret.setData(JSONObject.parseObject(order.getCardInfo()));
			return ret;
		}
		List<RoseskiOrderDtl> lst = roseskiOrderDtlMapper.listByOrderNo(orderNo);
		JSONObject obj = queryCardInfo(lst);
		Object o = obj.get("cardList");
		if(o != null) {
			List<Object> list = (List<Object>)o;
			if(list.size() > 0) {
				RoseskiOrder params = new RoseskiOrder();
				params.setOrderNo(orderNo);
				params.setCardInfo(obj.toJSONString());
				roseskiOrderMapper.updateByPrimaryKeySelective(params);
				ret.setData(obj);
				return ret;
			}
		}
		ret.setCode(ErrorCodeEnum.UNKNOWN.getCode());
		ret.setMessage("获取卡券信息失败");
		return ret;
	}

}
